﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Prsrp
{
    /// <summary>
    /// Base class for any hero in the game.
    /// </summary>
    public class BaseHero : BaseCharacter
    {
        public void HandleKeyboardInputs()
        {
            HandleLevitateRequest();
            HandleShootRequest();
            ExecuteStateFunction();
        }

        #region Properties

        // Score
        public Int32 miScore = 0;

        // Life
        public int miNbOfLifes;
        public int miNbOfContinues;

        // Weapon Ammo
        public int miAmmo;
        public int miMaxAmmo;

        public float mfLife = 0; // unused for now

        #endregion

        #region States Properties

        /// <summary>
        /// Hero Specific States
        /// </summary>
        public enum BaseHeroStates
        {            
            kRunning = BaseCharacterStates.kEnd,
            kJumping, // todo
            kCrouched,
            kShooting,
            kDead     // todo
        }

        public new void LoadStates()
        {
            base.LoadStates();
            DefineState(BaseHeroStates.kRunning, OnRunning);
            //DefineState(BaseHeroStates.kJumping, null);
            DefineState(BaseHeroStates.kCrouched, OnCrouching);
            DefineState(BaseHeroStates.kShooting, OnShooting);
            //DefineState(BaseHeroStates.kDead, null);
        }

        #endregion

        #region Utility Methods

        public void AddAmmo(int _iNbOfAmmo)
        {
            miAmmo += _iNbOfAmmo;
            if (miAmmo > miMaxAmmo) miAmmo = miMaxAmmo;
        }

        public void RemoveAmmo(int _iNbOfAmmo)
        {
            miAmmo -= _iNbOfAmmo;
            if (miAmmo < 0) miAmmo = 0;
        }

        #endregion

        #region Constructeurs

        public BaseHero()
        {
            mvSize = new Vector2(36, 48);
            miMaxAmmo = 20;
            miAmmo = 10;
            miNbOfLifes = 3;
            miNbOfContinues = 3;
            miHP = miMaxHP = 10;

            LoadStates();
            LoadSprites();
        }

        #endregion

        #region State Machine Methods

        void HandleShootRequest()
        {
            if (KeyboardManager.IsKeyPressedOnce(Keys.Space))
            {
                if (miAmmo > 0)
                {
                    RemoveAmmo(1);
                    StandardHeroBullet pNewBullet = new StandardHeroBullet(mvPos);
                    if (mbFlipSprite)
                    {
                        pNewBullet.mbFlipSprite = true;
                        pNewBullet.mvSpeed.X *= -1;
                    }
                    Game.Engine.CurrentLevel.AddProjectile(pNewBullet);
                    //SetState(States.kShooting);
                }
            }
        }

        void HandleLevitateRequest()
        {
            if (KeyboardManager.IsKeyDown(Keys.L))
            {
                mvPos.Y -= 5;
            }
        }

        void HandleJumpRequest()
        {
            if (KeyboardManager.IsKeyPressedOnce(Keys.Up))
            {
                mvSpeed.Y -= 30;
                SetState(BaseCharacterStates.kFalling);
            }
        }

        public override void OnIdle()
        {
            if (KeyboardManager.IsKeyDown(Keys.Left))
            {
                mbFlipSprite = true;
                SetState(BaseHeroStates.kRunning);
            }
            if (KeyboardManager.IsKeyDown(Keys.Right))
            {
                mbFlipSprite = false;
                SetState(BaseHeroStates.kRunning);
            }
            if (KeyboardManager.IsKeyDown(Keys.Down))
            {
                mvSpeed.X *= 0.25f;
                SetState(BaseHeroStates.kCrouched);
            }
            HandleJumpRequest();
        }

        void OnCrouching()
        {
            if (KeyboardManager.IsKeyDown(Keys.Left))
            {
                mbFlipSprite = true;
            }
            if (KeyboardManager.IsKeyDown(Keys.Right))
            {
                mbFlipSprite = false;
            }
            if (KeyboardManager.IsKeyUp(Keys.Down))
            {
                SetState(BaseCharacterStates.kIdle);
            }
        }

        void OnRunning()
        {
            if (KeyboardManager.IsKeyDown(Keys.Down))
            {
                mvSpeed.X *= 0.25f;
                SetState(BaseHeroStates.kCrouched);
            }
            if (KeyboardManager.IsKeyDown(Keys.Left))
            {
                mbFlipSprite = true;
                mvSpeed.X -= 1;
            }
            if (KeyboardManager.IsKeyDown(Keys.Right))
            {
                mbFlipSprite = false;
                mvSpeed.X += 1;
            }
            if (!(KeyboardManager.IsKeyDown(Keys.Left) || KeyboardManager.IsKeyDown(Keys.Right)))
            {
                SetState(BaseCharacterStates.kIdle);
            }
            HandleJumpRequest();
        }

        public override void OnFalling()
        {
            // The keyboard input can affect the fall.
            if (KeyboardManager.IsKeyDown(Keys.Left))
            {
                mbFlipSprite = true;
                mvSpeed.X -= 0.9f;
            }
            if (KeyboardManager.IsKeyDown(Keys.Right))
            {
                mbFlipSprite = false;
                mvSpeed.X += 0.9f;
            }
            if (KeyboardManager.IsKeyUp(Keys.Up))
            {
                mvSpeed.Y += 0.4f;
            }
            if (KeyboardManager.IsKeyUp(Keys.Down))
            {
                mvSpeed.Y -= 0.6f;
            }

            // Default Fall Behavior
            base.OnFalling();

            // Detect if the character touch the ground. (not perfect but work for now)
            // Maybe in the future use a @mbHitGround flag?
            if (mvSpeed.Y == 0)
            {
                SetState(BaseCharacterStates.kIdle);
            }
        }

        void OnShooting()
        {
            if (KeyboardManager.IsKeyUp(Keys.Space))
            {
                SetState(miOldState); // todo: rewrite this
            }
        }

        #endregion

        #region Ovverided Methods

        // This method MUST be implemented.
        public override void LoadSprites()
        {
            throw new NotImplementedException();
        }

        public override void Update()
        {
            // Update @mfLife
            float fDeltaTime = (float)Game.Engine.GameTime.ElapsedGameTime.TotalMilliseconds;
            mfLife += fDeltaTime;

            // Update Keyboard
            HandleKeyboardInputs();
        }

        public override void Draw()
        {
            // Draw Current Spite
            Animation pCurSprite = mtabStateSprites[miCurState];
            pCurSprite.Draw(mvPos, mfScale, mbFlipSprite);
        }

        #endregion
    }
}
